﻿using GENERIC.Respository.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace GENERIC.Respository
{
    /// <summary>
    /// Classe du repository générique
    /// </summary>
    /// <typeparam name="TEntity">Type de l'entité</typeparam>
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : class, new()
    {
        #region Constructor

        /// <summary>
        /// Nouvelle instance
        /// </summary>
        /// <param name="set">Set</param>
        public Repository(IGENERICSet<TEntity> set)
        {
            Set = set;
        }

        #endregion

        #region Properties

        private IGENERICSet<TEntity> Set { get; set; }

        #endregion

        #region Methods

        /// <summary>
        /// Obtient un ensemble d'entités
        /// </summary>
        /// <returns>un ensemble d'entités</returns>
        public IQueryable<TEntity> Get()
        {
            return Set.Get();
        }

        /// <summary>
        /// Insértion d'une entité
        /// </summary>
        /// <param name="entity">Entié à insérer</param>
        public virtual void Insert(TEntity entity)
        {
            Set.Insert(entity);
        }

        /// <summary>
        /// Mettre à jour une entité
        /// </summary>
        /// <param name="entity">Entité à mettre à jour</param>
        public virtual void Update(TEntity entity)
        {
            Set.Update(entity);
        }

        /// <summary>
        /// Suppression d'une entité
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Delete(TEntity entity)
        {
            Set.Delete(entity);
        }

        /// <summary>
        /// Obtient une collection d'entités
        /// </summary>
        /// <param name="expression">Critère de séléction</param>
        /// <returns></returns>
        public IQueryable<TEntity> Get(System.Linq.Expressions.Expression<Func<TEntity, bool>> expression)
        {
            if (expression == null) return Get();
            return Get().Where(expression);
        }

        /// <summary>
        /// Obtenir une collection d'entités en asynchrone
        /// </summary>
        /// <param name="expression">Critère de séléction</param>
        /// <param name="callback">Collection d'entité</param>
        /// <returns>Résultat</returns>
        public bool GetAsync(Expression<Func<TEntity, bool>> expression, Action<AsyncResponse, IQueryable<TEntity>> callback)
        {
            // Obtention du thread UI
            var UISyncContext = SynchronizationContext.Current;
            // Définition de l’appel
            WaitCallback waitCallBack =
            param =>
            {
                var response = new AsyncResponse();
                IQueryable<TEntity> retour = default(IQueryable<TEntity>);
                try
                {
                    // On obtient la liste des éléments
                    retour = Get((Expression<Func<TEntity, bool>>)param);
                }
                catch (Exception e)
                {
                    response.HasError = true;
                    response.ErrorMessage = e.Message;
                }
                finally
                {
                    // On exécute le callback sur le Thread UI
                    UISyncContext.Post(cParam => callback(response, (IQueryable<TEntity>)cParam), retour);
                }
            };
            //Lancement effectif du traitement
            return ThreadPool.QueueUserWorkItem(waitCallBack, expression.Body);
        }

        #endregion
    }
}
